import {RECORDER_INTERFACE, RECORDER_TYPE} from "./recorder_interface";

class ScriptRecorder implements RECORDER_INTERFACE {
    private scriptProcessorNode?: any;
    private streamSource?: any;
    private receiverCb?: (data: Float32Array) => void;
    private errorCb?: (e: any) => void;
    private isStarted: boolean;
    private bufferCache?: Float32Array;
    private bufferCacheOffset: number;

    constructor(private audioContext: any, private stream: any) {
        this.isStarted = false;
        this.bufferCacheOffset = 0;
    }

    getSampleRate(): number {
        return 16000;
    }

    getRecorderType(): number {
        return RECORDER_TYPE.SCRIPT_RECORDER;
    }

    connect(): Promise<boolean> {
        if (this.isSupport()) {
            let frameCount = this.getSampleRate() / 50;
            let fn = this.audioContext.createScriptProcessor || this.audioContext.createJavaScriptNode;
            // 2048 足够48000的采样率了
            this.scriptProcessorNode = fn.call(this.audioContext, 2048, 1, 1);
            this.streamSource = this.audioContext.createMediaStreamSource(this.stream);
            let dst = this.audioContext.destination;
            const cmsdTxt = "createMediaStreamDestination";
            if (this.audioContext[cmsdTxt]) {
                dst = this.audioContext[cmsdTxt]();
            }

            this.streamSource.connect(this.scriptProcessorNode);
            this.scriptProcessorNode.connect(dst);

            this.scriptProcessorNode.onaudioprocess = (e: AudioProcessingEvent) => {
                let data: any = e.inputBuffer.getChannelData(0);

                if (this.isStarted) {
                    this.bufferCache!.set(data, this.bufferCacheOffset);
                    this.bufferCacheOffset += data.length;

                    while (this.receiverCb && this.bufferCacheOffset >= frameCount) {
                        this.receiverCb(this.bufferCache!.slice(0, frameCount));
                        this.bufferCache!.copyWithin(0, frameCount, this.bufferCacheOffset);
                        this.bufferCacheOffset -= frameCount;
                    }
                }

                data = null;
            }

            return Promise.resolve(true);
        }

        return Promise.reject("录音器不支持");
    }

    disconnect(): Promise<boolean> {
        if (this.streamSource) {
            this.streamSource.disconnect();
            this.streamSource = undefined;
        }

        if (this.scriptProcessorNode) {
            this.scriptProcessorNode.disconnect();
            this.scriptProcessorNode = undefined;
        }

        return Promise.resolve(true);
    }

    isSupport(): boolean {
        return this.audioContext.createScriptProcessor || this.audioContext.createJavaScriptNode;
    }

    onDataReceive(fn: (data: any) => void): void {
        this.receiverCb = fn;
    }

    onError(fn: (e: any) => void): void {
        this.errorCb = fn;
    }

    start(): Promise<boolean> {
        if (!this.isStarted) {
            this.isStarted = true;
            this.bufferCacheOffset = 0;
            this.bufferCache = new Float32Array(4096);
        }
        return Promise.resolve(true);
    }

    stop(): Promise<boolean> {
        if (this.isStarted) {
            this.isStarted = false;
            this.bufferCache = undefined;
        }
        return Promise.resolve(true);
    }

}

export {ScriptRecorder}
